<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
    <style>
        html body {
            height: 100%;
            width: 100%;
            margin: 0;
            padding: 0;
            overflow: hidden;
        }

        #tooltip {
            position: absolute;
            z-index: 2;
            background: white;
            padding: 10px;
            border-radius: 2px;
            visibility: hidden;
        }
    </style>
</head>

<body>
    <script src="./three.js"></script>
    <canvas id="canvas" width="1000" height="1000"></canvas>
    <div id="tooltip"></div>
    <script type="module">
        import { InstancedFlow, Flow } from './flow.js'
        import { OBJLoader } from './obj.js'
        import { MTLLoader } from './mtl.js'
        import { GLTFLoader } from './gltf.js'
        class Template {

            constructor(canvas, view) {
                this.canvas = canvas
                this.view = view
                this.scene = new THREE.Scene()
            }

            //初始化场景
            init() {
                this.setCamera()
                this.setRenderer()
            }

            // 设置渲染器
            setRenderer() {
                this.renderer = new THREE.WebGLRenderer({
                    canvas: this.canvas,
                })
                this.renderer.setPixelRatio(window.devicePixelRatio)
                // 设置画布的大小
                this.renderer.setSize(this.view.width, this.view.height)
            }

            // 新建透视相机
            setCamera() {
                // 第二参数就是 长度和宽度比 默认采用浏览器  返回以像素为单位的窗口的内部宽度和高度
                this.camera = new THREE.PerspectiveCamera(75, this.view.width / this.view.height, 1, 3000)
                this.camera.position.z = 200
                this.scene.add(this.camera)
            }

            //渲染
            render() {
                if (this.renderer && this.camera) {
                    this.renderer.render(this.scene, this.camera)
                }
            }
        }
        class Scence extends Template {
            constructor(canvas, view) {
                super(canvas, view)
                this.init()
                this.updateBg()
                this.count = 100
                this.curveHandles = []
                this.addLight()
                this.create3dCurve()
                this.load3dText()
                //this.loadtree()
                this.addFog()
                this.addGroud()
                this.addMusic()
                this.addSnowParticle()
                this.loadBindDun()
            }

            updateBg() {
                if (this.renderer) {
                    this.renderer.setClearColor('rgb(255,255,255)', 1.0)
                }
            }

            // 增加一个地面
            addGroud() {
                const plane = new THREE.PlaneGeometry(1000, 1000)
                const material = new THREE.MeshPhongMaterial({
                    map: new THREE.TextureLoader().load('./edge.jpg'),
                })
                if (material) {
                    if (material.map) {
                        material.map.wrapS = THREE.RepeatWrapping
                        material.map.wrapT = THREE.RepeatWrapping
                        material.map.repeat.x = 30
                    }
                    const ground = new THREE.Mesh(plane, material)
                    ground.position.set(0, -80, 0)
                    ground.receiveShadow = true
                    ground.rotation.x = -Math.PI / 2
                    ground.rotation.z = -Math.PI / 2
                    ground.position.y = -1.5
                    this.scene.add(ground)
                }
            }

            // 新建透视相机
            setCamera() {
                // 第二参数就是 长度和宽度比 默认采用浏览器  返回以像素为单位的窗口的内部宽度和高度
                this.camera = new THREE.PerspectiveCamera(60, this.view.width / this.view.height, 1, 1000)
                this.camera.position.z = 200
                this.camera.position.x = 0
                this.camera.position.y = 30
                this.camera.lookAt(this.scene.position)
            }

            addLight() {
                const light = new THREE.PointLight(0xffaa33)
                light.castShadow = true
                light.position.set(0, 20, 0)
                light.intensity = 0.5
                this.scene.add(light)
                const light2 = new THREE.AmbientLight(0x222244)
                light2.castShadow = true
                light2.intensity = 3
                this.scene.add(light2)
            }


            addMusic() {
                const listener = new THREE.AudioListener();
                this.camera.add(listener);
                // 创建一个非位置音频对象  用来控制播放
                const audio = new THREE.Audio(listener);
                // 创建一个音频加载器对象
                const audioLoader = new THREE.AudioLoader();
                // 加载音频文件，返回一个音频缓冲区对象作为回调函数参数
                audioLoader.load('./music.mp3', function (AudioBuffer) {
                    // console.log(AudioBuffer)
                    // 音频缓冲区对象关联到音频对象audio
                    audio.setBuffer(AudioBuffer);
                    audio.setLoop(false); //是否循环
                    audio.setVolume(1); //音量
                    // 播放缓冲区中的音频数据
                    audio.pause()
                    audio.play(); //play播放、stop停止、pause暂停
                });
            }
            // 增加雾的效果
            addFog() {
                this.scene.fog = new THREE.FogExp2(0x000000, 0.0008)
            }

            // 加载圣诞树模型
            loadtree() {
                const obj = new OBJLoader() //obj加载器
                const mtl = new MTLLoader() //材质文件加载器
                mtl.load('./tree/12150_Christmas_Tree_V2_L2.mtl', (materials) => {
                    // 返回一个包含材质的对象MaterialCreator
                    //obj的模型会和MaterialCreator包含的材质对应起来
                    obj.setMaterials(materials)
                    obj.load('./tree/12150_Christmas_Tree_V2_L2.obj', (tree) => {
                        //tree.receiveShadow = true;
                        tree.castShadow = true
                        this.tree = tree
                        this.tree.scale.set(0.4, 0.4, 0.4) //放大obj组对象

                        // 先绕Y轴旋转 在绕 x 轴旋转
                        const matrix = new THREE.Matrix4().makeRotationY(Math.PI / 2).makeRotationX(-Math.PI / 2)
                        this.tree.rotation.setFromRotationMatrix(matrix)
                        this.tree.position.set(0, -5, 0)
                        this.scene.add(this.tree) //返回的组对象插入场景中
                    })
                })
            }

            loadBindDun() {
                const loader = new GLTFLoader();
                loader.load('./model/bingdwendwen.glb', (mesh) => {
                    mesh.scene.traverse(child => {
                        if (child.isMesh) {
                            // 内部
                            if (child.name === 'oldtiger001') {
                                child.material.metalness = .5
                                child.material.roughness = .8
                            }
                            // 半透明外壳
                            if (child.name === 'oldtiger002') {
                                child.material.transparent = true;
                                child.material.opacity = .5
                                child.material.metalness = .2
                                child.material.roughness = 0
                                child.material.refractionRatio = 1
                                child.castShadow = true;
                            }
                        }
                    });
                    mesh.scene.rotation.y = Math.PI / 24;
                    mesh.scene.position.set(0, 0, 60);
                    mesh.scene.scale.set(50, 50, 50);
                    // this.scene.add(this.flow.object3D)
                    this.scene.add(mesh.scene);

                })
            }

            // 加载雪花类型
            addSnowParticle() {
                const geo = new THREE.BufferGeometry()
                // 设置1000个顶点
                const vertices = []
                for (let i = 0; i < 10000; i++) {
                    const x = Math.random() * 2000 - 1000
                    const y = Math.random() * 2000 - 1000
                    const z = Math.random() * 2000 - 1000
                    vertices.push(x, y, z)
                }
                geo.setAttribute('position', new THREE.Float32BufferAttribute(vertices, 3))
                // 加载雪花贴图
                const texture = new THREE.TextureLoader().load(
                    './snow.png',
                )
                const material = new THREE.PointsMaterial({
                    size: 50,
                    map: texture,
                    blending: THREE.AdditiveBlending,
                    depthTest: false,
                    transparent: true,
                })
                material.color.setHSL(0.9, 0.05, 0.5)

                const particles = new THREE.Points(geo, material)

                particles.rotation.x = Math.random() * 6
                particles.rotation.y = Math.random() * 6
                particles.rotation.z = Math.random() * 6

                this.scene.add(particles)
                this.particle = particles
            }

            load3dText() {
                const loader = new THREE.FontLoader()
                loader.load('https://cdn.poizon.com/node-common/5121fb603fef9b5ae54eefe08b2faba7.json', (font) => {
                    const geometry = new THREE.TextGeometry('我是一个冰墩墩!', {
                        font: font,
                        size: 5,
                        height: 1,
                        curveSegments: 12,
                        bevelEnabled: true,
                        bevelThickness: 0.02,
                        bevelSize: 0.01,
                        bevelOffset: 0,
                        bevelSegments: 5,
                    })

                    geometry.rotateZ(-Math.PI)

                    const material = new THREE.MeshStandardMaterial({
                        color: 0x99ffff,
                    })
                    const numberOfInstances = 1
                    const objectToCurve = new THREE.Mesh(geometry, material)
                    this.flow2 = new InstancedFlow(1, undefined, geometry, material);
                    this.flow2.updateCurve(0, this.curve)
                    this.scene.add(this.flow2.object3D)
                    this.flow2.setCurve(0, 0);
                })
            }
            // 创建3d 曲线
            create3dCurve() {
                const value = 40
                const initialPoints = [
                    { x: value, y: 0, z: -value },
                    { x: value, y: 0, z: value },
                    { x: -value, y: 0, z: value },
                    { x: -value, y: 0, z: -value },
                ]
                const boxGeometry = new THREE.BoxGeometry(5, 5, 5)
                const boxMaterial = new THREE.MeshBasicMaterial({ color: 0x50ff22 })
                for (const handlePos of initialPoints) {
                    const { x, y, z } = handlePos
                    const handle = new THREE.Mesh(boxGeometry, boxMaterial)
                    handle.position.copy(new THREE.Vector3(x, y, z))
                    this.curveHandles.push(handle)
                    // this.scene.add(handle)
                }
                this.curve = new THREE.CatmullRomCurve3(
                    this.curveHandles.map((handle) => handle.position),
                    true,
                    'centripetal',
                )
                const points = this.curve.getPoints(50)
                const line = new THREE.LineLoop(
                    new THREE.BufferGeometry().setFromPoints(points),
                    new THREE.LineBasicMaterial({

                        visible: false,
                        // linecap: 'round', //ignored by WebGLRenderer
                        // linejoin: 'round'
                    }),
                )
                console.error(line.position, '222')
                this.scene.add(line)
            }

            updateCamera(time) {
                // if (this.camera) {
                //     this.camera.position.x = Math.sin(time * 0.0005) * 150
                //     this.camera.position.z = 100 + Math.cos(time * 0.0005) * 150
                //     this.camera.position.y = 30 + Math.cos(time * 0.0005) * 30
                //     this.camera.lookAt(new THREE.Vector3(0, -20, 0))
                // }
            }

            render() {
                super.render()
                const time = Date.now() * 0.00005
                // if (this.particle) {
                //     this.particle.rotation.y = time
                // }
                this.updateCamera(Date.now())
                if (this.flow && this.flow2) {
                    this.flow.moveAlongCurve(0.02)
                    this.flow2.moveAlongCurve(0.002)
                }
                requestAnimationFrame(this.render.bind(this))

            }
        }
        let canvas = document.getElementById('canvas')
        let scene = new Scence(canvas, {
            width: window.innerWidth,
            height: window.innerHeight
        })
        scene.render()

    </script>
</body>

</html>